package container.map;

import java.util.HashMap;
import java.util.UUID;

/**
 * @author: 李德才
 * @description:
 * @create: 2020-12-13 18:20
 **/
public class Test_HashMap {
    /**
     * HashMap 不使用 synchronized ，线程不安全，效率较高
     * <p>
     * 问题出在：
     * if ((p = tab[i = (n - 1) & hash]) == null) //
     * tab[i] = newNode(hash, key, value, null);
     * 代码是判断插入的 key 是否出现hash碰撞，假设两个线程A、B都在进行put操作，并且hash函数计算出的插入下标是相同的，
     * 当线程A执行完上面的代码后由于时间片耗尽导致被挂起，而线程B得到时间片后在该下标处插入了元素，完成了正常的插入，
     * 然后线程A获得时间片，由于之前已经进行了hash碰撞的判断，所有此时不会再进行判断，而是直接进行插入，
     * 这就导致了线程B插入的数据被线程A覆盖了，从而线程不安全
     */
    static HashMap<UUID, UUID> m = new HashMap<>();
    static int count = Constants.COUNT;
    static UUID[] keys = new UUID[count];
    static UUID[] values = new UUID[count];
    static final int THREAD_COUNT = Constants.THREAD_COUNT;

    static {
        for (int i = 0; i < count; i++) {
            keys[i] = UUID.randomUUID();
            values[i] = UUID.randomUUID();
        }
    }

    static class MyThread extends Thread {
        int start;
        int gap = count / THREAD_COUNT;

        public MyThread(int start) {
            this.start = start;
        }

        @Override
        public void run() {
            for (int i = start; i < start + gap; i++) {
                m.put(keys[i], values[i]);
            }
        }
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        Thread[] threads = new Thread[THREAD_COUNT];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(i * (count / THREAD_COUNT));
        }
        for (Thread t : threads) {
            t.start();
        }
        for (Thread t : threads) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
        System.out.println(m.size());
    }

}
